package com.dianping.cat.task;

import com.dianping.cat.Cat;
import com.dianping.cat.helper.TimeHelper;
import com.dianping.cat.message.Transaction;
import org.unidal.helper.Threads;
import org.unidal.helper.Threads.Task;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;

public class TimerSyncTask implements Task {

    private static final long DURATION = TimeHelper.ONE_MINUTE;

    private static final TimerSyncTask m_instance = new TimerSyncTask();

    private static final ExecutorService s_threadPool = Threads.forPool().getFixedThreadPool("Cat-ConfigSyncTask", 3);

    private static boolean m_active = false;

    private final List<SyncHandler> m_handlers = new ArrayList<>();

    public static TimerSyncTask getInstance() {
        if (!m_active) {
            synchronized (TimerSyncTask.class) {
                if (!m_active) {
                    Threads.forGroup("cat").start(m_instance);
                    m_active = true;
                }
            }
        }
        return m_instance;
    }

    @Override
    public String getName() {
        return "timer-sync-task";
    }

    public void register(SyncHandler handler) {
        synchronized (this) {
            m_handlers.add(handler);
        }
    }

    @Override
    public void run() {
        boolean active = TimeHelper.sleepToNextMinute();

        while (active) {
            long current = System.currentTimeMillis();

            for (final SyncHandler handler : m_handlers) {
                s_threadPool.submit(new Runnable() {
                    @Override
                    public void run() {
                        final Transaction t = Cat.newTransaction("TimerSync", handler.getName());

                        try {
                            handler.handle();
                            t.setStatus(Transaction.SUCCESS);
                        } catch (Exception e) {
                            t.setStatus(e);
                            Cat.logError(e);
                        } finally {
                            t.complete();
                        }
                    }
                });
            }

            long duration = System.currentTimeMillis() - current;

            try {
                if (duration < DURATION) {
                    Thread.sleep(DURATION - duration);
                }
            } catch (InterruptedException e) {
                active = false;
            }
        }
    }

    @Override
    public void shutdown() {
    }

    public interface SyncHandler {

        String getName();

        void handle() throws Exception;
    }
}
